Requirements (Functional and Non-Functional)
The Course Catalog app must meet both functional and non-functional requirements.
Core Features
- Course list with pull-to-refresh and pagination.
- Course detail screen with full description, syllabus bullets, instructor info, and enroll/favorite button.
- Search bar with debounced queries and live results.
- Favorites view persisted locally.
- Offline cache: last successful course list stored and shown when offline.
- Error and empty states with retry options.
Non-Functional
- Clean architecture: separation of UI, state, services, and models.
- State management via Provider + ChangeNotifier (or Riverpod if preferred).
- Responsive UI for narrow and wide screens.
- Accessible buttons and clear semantic labels.
- Automated unit tests for model parsing and at least two widget tests for list and detail flows.
Architecture and Folders
A well-organized project structure is essential for maintainability.
High-Level Layers
- Presentation (screens, widgets)
- State (providers / notifiers)
- Domain/models (Course, Instructor, SyllabusItem)
- Data/services (API client, local cache)
Suggested Folder Layout
lib/
main.dart
app.dart
models/
course.dart
instructor.dart
services/
api_service.dart
cache_service.dart
providers/
course_provider.dart
screens/
home_screen.dart
course_detail_screen.dart
favorites_screen.dart
search_screen.dart
widgets/
course_card.dart
course_list.dart
course_filter_bar.dart
utils/
constants.dart
debounce.dart
State Flow
UI → Provider (CourseProvider) → Service (ApiService / CacheService) → Models → Provider updates UI via notifyListeners.
Data Models and API Contract
Defining clear data models and API contracts ensures consistency.
Course Model (Required Fields)
id: Stringtitle: Stringsubtitle: Stringdescription: Stringprice: double(nullable for free)imageUrl: Stringinstructor: Instructor(id, name, avatarUrl)syllabus: List<String>orList<SyllabusItem>rating: doubletags: List<String>
API Endpoints (Mockable)
GET /courses?page=1&limit=20&query=flutter— returns paginated list with total/count.GET /courses/{id}— returns full course details.- Optional:
GET /instructors/{id}
Local Cache
Persist last loaded page (JSON) and favorites (list of course ids) using SharedPreferences or local file. Use JSON serialization in models: toJson/fromJson.
UI Screens and Key Widgets
Each screen serves a specific purpose in the user journey.
HomeScreen
- Top: AppBar with search icon and favorites shortcut.
- Body: CourseList (ListView.builder or GridView.builder depending on width) with pull-to-refresh and infinite scroll loader.
- Each item: CourseCard showing image, title, subtitle, rating, price, favorite icon.
CourseDetailScreen
- Large header image, title, instructor row, rating, price, enroll button, favorite toggle, expandable syllabus list, and share button.
- Use SliverAppBar for collapsible image on larger screens (optional).
SearchScreen (or inline search)
- Debounced search input; shows loading, suggestions, and results.
- Cancel previous network call on new query.
FavoritesScreen
- Shows favorited courses from local store.
- Allow unfavorite and tap to open details.
Shared Widgets
- CourseCard (configurable compact/expanded)
- CourseList (accepts items, loading state, onEndReached callback)
- ErrorView, EmptyView, LoadingFooter
Step-by-Step Implementation Plan
Follow this structured approach to build the app systematically.
1. Project Bootstrap
Create flutter project, set up folder layout, add dependencies: provider, http, shared_preferences, cached_network_image, flutter_test, intl (optional). Add basic ThemeData in app.dart and wire Provider scope in main.dart.
2. Models
Implement Course and Instructor with factory fromJson(Map) and toJson(). Add simple validation in factories (throw FormatException if essential fields missing). Add unit tests to validate parsing and error handling with sample JSON.
3. Services
ApiService: implement methods to fetch courses and course details. Use http and return parsed models. Add error handling and small retry/backoff wrapper if desired. CacheService: implement read/write of cached course list and favorites using SharedPreferences or local file. Provide methods: saveCourses(json), loadCourses(), saveFavorites(List<String>), loadFavorites().
4. Provider (CourseProvider)
Expose: List<Course> courses, bool loading, bool loadingMore, String? error, List<String> favorites, methods: loadInitial(), loadMore(), refresh(), toggleFavorite(courseId), search(query). Implement pagination guards (isLoadingMore flag) and network error handling. On network success update cache.
5. UI: HomeScreen and CourseList
Build CourseCard with accessible semantics and tappable favorite icon. Use cached_network_image for images. Implement pull-to-refresh (RefreshIndicator) calling provider.refresh(). Attach ScrollController for infinite scroll, invoking provider.loadMore() when near bottom.
6. Detail Screen and Favorites
Push detail via Navigator; fetch detailed course from provider or ApiService if not present. Implement favorite toggle that updates provider and cache.
7. Search
Implement Debounce utility. Wire search input to provider.search(query) with 300–500ms debounce and a small loading indicator inside the search bar.
8. Offline and Cache Behavior
On startup, provider attempts loadInitial(): try network, on failure load cache and set offline error state. Display cached list with a banner indicating offline mode and Retry button.
9. Tests
Unit tests: model parsing, cache read/write stubs (mock SharedPreferences). Widget tests: pump HomeScreen with mocked provider that returns test courses; verify list displays and tapping course opens detail.
10. Polish and Accessibility
Add semanticsLabels for images/buttons, ensure tap targets exceed minimum size, support dark theme toggle if time permits.
11. Build and Deliver
Run flutter build apk –release, test on device. Provide README with run instructions, test coverage, and known issues.
Testing, Deployment, and Deliverables
Proper testing and deployment ensure a quality deliverable.
Tests
- Unit tests for model parsing and providers' business logic (pagination guard, favorites).
- Widget tests for HomeScreen (list displays) and CourseDetailScreen (renders key info, toggles favorite).
Deployment
- Prepare app icon and splash screen assets.
- For Android: set versioning in build.gradle, sign release APK or AAB, follow Play Console steps.
- For iOS: configure Xcode, bundle id, provisioning profiles.
- Provide an APK or instructions to run on emulator with flutter run.
Deliverables Checklist
- Source code repository with clear commits.
- README: setup, architecture notes, how to run tests, and design decisions.
- Unit and widget tests passing.
- APK or emulator run instructions.
- Short demo video or screenshots (optional).
Session Assignment
Complete the full Course Catalog app with at least: Home list with pagination, Course detail screen, Search, Favorites persisted locally, Offline cache fallback, Unit tests for models, and two widget tests.
Submit: Git repo link or zipped project, README describing architecture and trade-offs (250–400 words), test results, and at least three screenshots (list, detail, favorites).